package main

import "fmt"

/**
Panic 异常
Go 语言是一门静态的强类型语言，很多问题都尽可能地在编译时捕获，但是有一些只能在运行时检查，比如数组越界访问、不相同的类型强制转换等，这类运行时的问题会引起 panic 异常。
除了运行时可以产生 panic 外，我们自己也可以抛出 panic 异常。假设我需要连接 MySQL 数据库，可以写一个连接 MySQL 的函数connectMySQL，如下面的代码所示：
*/

func connectMySQL(ip, username, password string) {
	if ip == "" {
		panic("ip不能为空")
	}
	//省略其他代码
}

//func main() {
//	connectMySQL("","","")
//}

/**
panic 是 Go 语言内置的函数，可以接受 interface{} 类型的参数，也就是任何类型的值都可以传递给 panic 函数，如下所示：
func panic(v interface{})
interface{} 是空接口的意思，在 Go 语言中代表任意类型。

panic 异常是一种非常严重的情况，会让程序中断运行，使程序崩溃，所以如果是不影响程序运行的错误，不要使用 panic，使用普通错误 error 即可。
*/

// 使用recover捕获panic异常
/**
通常情况下，我们不对 panic 异常做任何处理，因为既然它是影响程序运行的异常，就让它直接崩溃即可。
但是也的确有一些特例，比如在程序崩溃前做一些资源释放的处理，这时候就需要从 panic 异常中恢复，才能完成处理。
在 Go 语言中，可以通过内置的 recover 函数恢复 panic 异常。因为在程序 panic 异常崩溃的时候，只有被 defer 修饰的函数才能被执行，所以 recover 函数要结合 defer 关键字使用才能生效。
下面的示例是通过 defer 关键字 + 匿名函数 + recover 函数从 panic 异常中恢复的方式。
*/

func main() {
	defer func() {
		// 通过这个输出的结果也可以发现，recover 函数返回的值就是通过 panic 函数传递的参数值。
		if p := recover(); p != nil {
			fmt.Println(p)
		}
	}()
	connectMySQL("", "", "")
}
